home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Devices / DriverGestaltExplorer / DriverGestaltExplorer.c next >
Encoding:
Text File  |  1998-04-28  |  25.0 KB  |  842 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        DriverGestaltExplorer.c
  3.  
  4.     Contains:    A sample and tool for exploring Driver Gestalt.
  5.  
  6.     Written by:    Quinn "The Eskimo!"
  7.  
  8.     Copyright:    © 1998 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.     You may incorporate this sample code into your applications without
  13.     restriction, though the sample code has been provided "AS IS" and the
  14.     responsibility for its operation is 100% yours.  However, what you are
  15.     not permitted to do is to redistribute the source as "DSC Sample Code"
  16.     after having made changes. If you're going to re-distribute the source,
  17.     we require that you make it clear in the source that the code was
  18.     descended from Apple Sample Code, but that you've made changes.
  19. */
  20.  
  21. /////////////////////////////////////////////////////////////////
  22. // Standard Mac OS Interfaces
  23.  
  24. #import <DriverGestalt.h>
  25.  
  26. /////////////////////////////////////////////////////////////////
  27. // Standard C Libraries
  28.  
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32.  
  33. /////////////////////////////////////////////////////////////////
  34. // We use some of the utility routines from TradDriverLoaderLib,
  35. // which prevents us having to reinvent the wheel.
  36.  
  37. #include "TradDriverLoaderLib.h"
  38.  
  39. /////////////////////////////////////////////////////////////////
  40. #pragma mark ----- Utility Routines -----
  41.  
  42. static void QAssert(Boolean mustBeTrue)
  43.     // Stardard Assert functionality.  How many times have
  44.     // I written this?  How much time would I save if it was
  45.     // built into the OS?
  46. {
  47.     if ( ! mustBeTrue ) {
  48.         DebugStr("\pQAssert: Assertion failure");
  49.     }
  50. }
  51.  
  52. static DriverRefNum MapDriveToRefNum(SInt16 drive)
  53.     // Walks the drive queue looking for the given drive
  54.     // and returns the driver reference number of the driver
  55.     // controlling the drive.
  56.     //
  57.     // I would have used UTFindDrive for this, but calling
  58.     // it from PowerPC is tricky.
  59. {
  60.     DrvQElPtr thisDrv;
  61.     
  62.     thisDrv = (DrvQElPtr) GetDrvQHdr()->qHead;
  63.     while (thisDrv != nil) {
  64.         if (thisDrv->dQDrive == drive) {
  65.             return thisDrv->dQRefNum;
  66.         }
  67.         thisDrv = (DrvQElPtr) thisDrv->qLink;
  68.     }
  69.     return 0;
  70. }
  71.  
  72. static Boolean DriveSupportsDriverGestalt(SInt16 drive)
  73.     // Returns true if the driver controlling the
  74.     // supplied drive supports Driver Gestalt.
  75. {
  76.     OSErr junk;
  77.     DriverRefNum refNum;
  78.     DriverFlags driverFlags;
  79.     
  80.     refNum = MapDriveToRefNum(drive);
  81.     
  82.     junk = TradGetDriverInformation(refNum, nil, &driverFlags, nil, nil);
  83.     QAssert(junk == noErr);
  84.     return TradDriverGestaltIsOn(driverFlags);
  85. }
  86.  
  87. static StringPtr RefNumToName(DriverRefNum refNum)
  88.     // Returns the (Pascal string) name of the driver with the supplied
  89.     // refNum.  Basically a wrapper around TradDriverLoaderLib.
  90.     // 
  91.     // Note that the routine returns the address of a static
  92.     // buffer, so you don't have to dispose it but you must
  93.     // be careful not to call the routine again until you're
  94.     // done with the result.
  95. {
  96.     static Str255 nonReentrantBuffer;
  97.     OSErr junk;
  98.  
  99.     junk = TradGetDriverInformation(refNum, nil, nil, nonReentrantBuffer, nil);
  100.     QAssert(junk == noErr);
  101.     return nonReentrantBuffer;
  102. }
  103.  
  104. static char *OSTypeToString(OSType selector)
  105.     // Returns a C string for the supplied selector.
  106.     // 
  107.     // Note that the routine returns the address of a static
  108.     // buffer, so you don't have to dispose it but you must
  109.     // be careful not to call the routine again until you're
  110.     // done with the result.
  111. {
  112.     static char nonReentrantBuffer[5];
  113.  
  114.     *((OSType*) nonReentrantBuffer) = selector;    
  115.     nonReentrantBuffer[4] = 0;
  116.     return nonReentrantBuffer;
  117. }
  118.  
  119. /////////////////////////////////////////////////////////////////
  120. #pragma mark ----- Data Table Types -----
  121.  
  122. // An array of OSTypeElement's is passed as the argument
  123. // to OSTypeDisplay.  The array is terminated by an element
  124. // whose name is nil.  This array allows OSTypeDisplay to
  125. // map an OSType to its string description.
  126.  
  127. struct OSTypeElement {
  128.     OSType value;
  129.     char*  name;
  130. };
  131. typedef struct OSTypeElement OSTypeElement;
  132.  
  133. // The address of a BooleanTable is passed as the argument
  134. // to BooleanDisplay.  The table allows BooleanDisplay to
  135. // map a Boolean result to a string description.
  136.  
  137. struct BooleanTable {
  138.     char *trueString;
  139.     char *falseString;
  140. };
  141. typedef struct BooleanTable BooleanTable;
  142.  
  143. // An array of FlagElement's is passed as the argument
  144. // to Flags16Display and Flags32Display, and hence on
  145. // to PrintFlags.  The array is terminated by an element
  146. // whose mask is 0.  This array allows PrintFlags to
  147. // test for the known flags in a flags UInt32 and print
  148. // out the corresponding textual descriptions.
  149.  
  150. struct FlagElement {
  151.     UInt32 mask;
  152.     char *trueString;
  153.     char *falseString;
  154. };
  155. typedef struct FlagElement FlagElement;
  156.  
  157. // A GestaltElement holds information about a single
  158. // DriverGestalt selector, including the selector itself,
  159. // a textual description of the selector (name), the address
  160. // of a routine that can print the response, and the argument
  161. // for that routine.
  162. //
  163. // The primary use of this type is in gGestaltList,
  164. // an array of these elements (terminated by an entry with
  165. // a selector of 0) which describes all the Driver Gestalt
  166. // selectors documented at the time this sample was last updated.
  167.  
  168. typedef void (*ResponseDisplayProc)(DriverGestaltParam *pb, void *arg);
  169.  
  170. struct GestaltElement {
  171.     OSType selector;
  172.     char*  name;
  173.     ResponseDisplayProc responseDisplayRoutine;
  174.     void*  responseDisplayArg;
  175. };
  176. typedef struct GestaltElement GestaltElement;
  177.  
  178. /////////////////////////////////////////////////////////////////
  179. #pragma mark ----- Response Printing -----
  180.  
  181. // The routines in this section are responsible for taking a
  182. // Driver Gestalt response and printing it to stdout.  They
  183. // all conform to the ResponseDisplayProc type and are referenced
  184. // by gGestaltList table.
  185. //
  186. // The routines are given in the order of most generic to most
  187. // specific.
  188.  
  189. static void DefaultDisplay(DriverGestaltParam *pb, void *arg)
  190.     // Prints a Driver Gestalt response for a selector we
  191.     // don't know about.  All we can do is print the four
  192.     // standard response fields as hex.
  193. {
  194.     #pragma unused(arg)
  195.     printf("  driverGestaltResponse  = %08lx\n", pb->driverGestaltResponse);
  196.     printf("  driverGestaltResponse1 = %08lx\n", pb->driverGestaltResponse1);
  197.     printf("  driverGestaltResponse2 = %08lx\n", pb->driverGestaltResponse2);
  198.     printf("  driverGestaltResponse3 = %08lx\n", pb->driverGestaltResponse3);
  199. }
  200.  
  201. static void OSTypeDisplay(DriverGestaltParam *pb, void *arg)
  202.     // Prints a Driver Gestalt response in driverGestaltResponse
  203.     // whose value is an OSType.  arg is a pointer to an array
  204.     // of OSTypeElements that describes the expected values
  205.     // and their textual descriptions.
  206. {
  207.     OSType response;
  208.     OSTypeElement *responseList;
  209.     Boolean found;
  210.     ItemCount thisIndex;
  211.     
  212.     response = (OSType) pb->driverGestaltResponse;
  213.     responseList = (OSTypeElement *) arg;
  214.  
  215.     // Search for response in the responseList.
  216.     
  217.     found = false;
  218.     thisIndex = 0;
  219.     while ( ! found && responseList[thisIndex].name != nil ) {
  220.         found = (responseList[thisIndex].value == response);
  221.         if ( ! found ) {
  222.             thisIndex += 1;
  223.         }
  224.     }
  225.     
  226.     // If we found it, print the response with its textual description,
  227.     // otherwise just print the response.
  228.     
  229.     if (found) {
  230.         printf("  Response = '%s' “%s”\n", OSTypeToString(response), responseList[thisIndex].name);
  231.     } else {
  232.         printf("  Response = '%s'\n", OSTypeToString(response));
  233.     }
  234. }
  235.  
  236. static void BooleanDisplay(DriverGestaltParam *pb, void *arg)
  237.     // Prints a Driver Gestalt response which is a Boolean in the
  238.     // first byte of driverGestaltResponse.  arg is a pointer to
  239.     // an array of BooleanElements that gives the textual descriptions
  240.     // for true and false.
  241. {
  242.     BooleanTable *booleanTable;
  243.     Boolean value;
  244.     
  245.     booleanTable = (BooleanTable *) arg;
  246.     value = *GetDriverGestaltBooleanResponse(pb);
  247.     switch (value) {
  248.         case true:
  249.             printf("  Response = %d “%s”\n", value, booleanTable->trueString);
  250.             break;
  251.         case false:
  252.             printf("  Response = %d “%s”\n", value, booleanTable->falseString);
  253.             break;
  254.         default:
  255.             printf("  Response = %d (Weird)\n", value);
  256.             break;
  257.     }
  258. }
  259.  
  260. static void PrintFlags(UInt32 flags, FlagElement flagList[])
  261.     // A utility routine called by Flags16Display and Flags32Display.
  262.     // flags is the response flags to be printed.  The routine
  263.     // prints both the value of flags and a textual description
  264.     // of the flags based on flagList, an array of FlagElements
  265.     // which describes the known flag masks and the textual
  266.     // descriptions for those masks.
  267. {
  268.     ItemCount thisIndex;
  269.     
  270.     printf("  Response = %08lx\n", flags);
  271.     thisIndex = 0;
  272.     while ( flagList[thisIndex].mask != 0 ) {
  273.         if ( (flags & flagList[thisIndex].mask) != 0 ) {
  274.             printf("    %s\n", flagList[thisIndex].trueString);
  275.         } else {
  276.             printf("    %s\n", flagList[thisIndex].falseString);
  277.         }
  278.         thisIndex += 1;
  279.     }
  280. }
  281.  
  282. static void Flags16Display(DriverGestaltParam *pb, void *arg)
  283.     // Prints a Driver Gestalt response which is a UInt32 in the
  284.     // first two bytes of driverGestaltResponse.  arg is a pointer to
  285.     // an array of FlagElements which describes the known flag masks and
  286.     // the textual descriptions for those masks.
  287. {
  288.     UInt32 flags;
  289.     
  290.     flags = *((UInt16 *) &pb->driverGestaltResponse);
  291.     PrintFlags(flags, arg);
  292. }
  293.  
  294. static void Flags32Display(DriverGestaltParam *pb, void *arg)
  295.     // Prints a Driver Gestalt response which is a UInt32 in the
  296.     // driverGestaltResponse.  arg is a pointer to an array of
  297.     // FlagElements which describes the known flag masks and
  298.     // the textual descriptions for those masks.
  299. {
  300.     UInt32 flags;
  301.     
  302.     flags = *((UInt32 *) &pb->driverGestaltResponse);
  303.     PrintFlags(flags, arg);
  304. }
  305.  
  306. static void PowerDisplay(DriverGestaltParam *pb, void *arg)
  307.     // Prints a Driver Gestalt power response, used by the
  308.     // various power rating selectors to return the
  309.     // power in microWatts.  arg is unused.
  310. {
  311.     #pragma unused(arg)
  312.     DriverGestaltPowerResponse* response;
  313.     
  314.     response = GetDriverGestaltPowerResponse(pb);
  315.     printf("  Response = %ld microWatts\n", response->powerValue);
  316. }
  317.  
  318. static void VersionDisplay(DriverGestaltParam *pb, void *arg)
  319.     // Prints a Driver Gestalt response which is a NumVersion in
  320.     // driverGestaltResponse.  arg is unused.
  321. {
  322.     #pragma unused(arg)
  323.     NumVersion version;
  324.     char versionString[256];
  325.     char tmpString[256];
  326.     char stageChar;
  327.     
  328.     version = *((NumVersion *) &pb->driverGestaltResponse);
  329.     
  330.     sprintf(versionString, "%d.%d", version.majorRev, (version.minorAndBugRev >> 4) & 0x0f);
  331.     if ( (version.minorAndBugRev & 0x0f) != 0 ) {
  332.         sprintf(tmpString, ".%d", version.minorAndBugRev & 0x0f);
  333.         strcat(versionString, tmpString);
  334.     }
  335.     if ( version.stage != finalStage || version.nonRelRev != 0 ) {
  336.         switch (version.stage) {
  337.             case finalStage:
  338.                 stageChar = 'f';
  339.                 break;
  340.             case betaStage:
  341.                 stageChar = 'b';
  342.                 break;
  343.             case alphaStage:
  344.                 stageChar = 'a';
  345.                 break;
  346.             case developStage:
  347.                 stageChar = 'd';
  348.                 break;
  349.             default:
  350.                 stageChar = '?';
  351.                 break;
  352.         }
  353.         sprintf(tmpString, "%c%d", stageChar, version.nonRelRev);
  354.         strcat(versionString, tmpString);
  355.     }
  356.  
  357.     printf("  Response = %s (%08lx)\n", versionString, pb->driverGestaltResponse);
  358. }
  359.  
  360. static void BootDisplay(DriverGestaltParam *pb, void *arg)
  361.     // Prints the response to the Driver Gestalt kdgBoot selector,
  362.     // which is a DriverGestaltBootResponse.  arg is unused.
  363. {
  364.     #pragma unused(arg)
  365.     DriverGestaltBootResponse* response;
  366.     
  367.     response = GetDriverGestaltBootResponse(pb);
  368.     printf("  extDev    = %d\n", response->extDev);
  369.     printf("  partition = %d\n", response->partition);
  370.     printf("  SIMSlot   = %d\n", response->SIMSlot);
  371.     printf("  SIMsRSRC  = %d\n", response->SIMsRSRC);
  372. }
  373.  
  374. static void PurgeDisplay(DriverGestaltParam *pb, void *arg)
  375.     // Prints the response to the Driver Gestalt kdgPurge selector,
  376.     // which is a DriverGestaltBootResponse.  arg is unused.
  377. {
  378.     #pragma unused(arg)
  379.     DriverGestaltPurgeResponse *response;
  380.     
  381.     response = GetDriverGestaltPurgeResponse(pb);
  382.  
  383.     PrintFlags(response->purgePermission, arg);
  384.     printf("  purgeDriverPointer = %08lx\n", response->purgeDriverPointer);
  385. }
  386.  
  387. static void FlushDisplay(DriverGestaltParam *pb, void *arg)
  388.     // Prints the response to the Driver Gestalt kdgFlush selector,
  389.     // which is a GetDriverGestaltFlushResponse.  arg is unused.
  390. {
  391.     #pragma unused(arg)
  392.     DriverGestaltFlushResponse* response;
  393.     char *tmpStr;
  394.     
  395.     response = GetDriverGestaltFlushResponse(pb);
  396.     if (response->canFlush) {
  397.         tmpStr = "Driver supports kdcFlush Driver Configure call";
  398.     } else {
  399.         tmpStr = "Driver does not support kdcFlush Driver Configure call";
  400.     }
  401.     printf("  canFlush = %d “%s”\n", response->canFlush, tmpStr);
  402.     if (response->needsFlush) {
  403.         tmpStr = "Driver needs flush when volume flushed";
  404.     } else {
  405.         tmpStr = "Driver does not need flush when volume flushed";
  406.     }
  407.     printf("  needsFlush = %d “%s”\n", response->needsFlush, tmpStr);
  408. }
  409.  
  410. static void MediaInfoDisplay(DriverGestaltParam *pb, void *arg)
  411.     // Prints the response to the Driver Gestalt kdgMediaInfo selector,
  412.     // which is a DriverGestaltMediaInfoResponse.  arg is unused.
  413. {
  414.     #pragma unused(arg)
  415.     DriverGestaltMediaInfoResponse* response;
  416.     
  417.     response = GetDriverGestaltMediaInfoResponse(pb);
  418.     printf("  numberBlocks = %ld\n", response->numberBlocks);
  419.     printf("  blockSize = %ld\n", response->blockSize);
  420.     switch (response->mediaType) {
  421.         case kMediaTypeUnknown:
  422.             printf("  mediaType = “unknown”\n");
  423.             break;
  424.         case kMediaTypeCDROM:
  425.             printf("  mediaType = “CD-ROM”\n");
  426.             break;
  427.         case kMediaTypeDVDROM:
  428.             printf("  mediaType = “DVD-ROM”\n");
  429.             break;
  430.         case kMediaTypeNoMedia:
  431.             printf("  mediaType = “no media”\n");
  432.             break;
  433.     }
  434. }
  435.  
  436. /////////////////////////////////////////////////////////////////
  437. #pragma mark ----- Data Tables -----
  438.  
  439. #pragma mark OSType Tables
  440.  
  441. // gInterfaceTypeList describes the expected results
  442. // from the kdgInterface selector.
  443.  
  444. static OSTypeElement gInterfaceTypeList[] = {
  445.     {kdgScsiIntf, "SCSI"},
  446.     {kdgPcmciaIntf, "PC Card"},
  447.     {kdgATAIntf, "ATA"},
  448.     {kdgFireWireIntf, "Firewire"},
  449.     {kdgExtBus, "External Bus"},
  450.     {0, nil}
  451. };
  452.  
  453. // gDeviceTypeList describes the expected results
  454. // from the kdgDeviceType selector.
  455.  
  456. static OSTypeElement gDeviceTypeList[] = {
  457.     {kdgDiskType, "Disk"},
  458.     {kdgTapeType, "Tape"},
  459.     {kdgPrinterType, "Printer"},
  460.     {kdgProcessorType, "Processor"},
  461.     {kdgWormType, "Write-Once, Read Many"},
  462.     {kdgCDType, "CD-ROM"},
  463.     {kdgFloppyType, "Floppy"},
  464.     {kdgScannerType, "Scanner"},
  465.     {kdgFileType, "File (ie disk image)"},
  466.     {kdgRemovableType, "Removable Disk"},
  467.     {0, nil}
  468. };
  469.  
  470. #pragma mark Boolean Tables
  471.  
  472. // Boolean results from various selectors.
  473.  
  474. static BooleanTable gSyncBooleanTable = { "Synchronous", "Asynchronous" };
  475. static BooleanTable gWideBooleanTable = { "Supports wide ioPosMode", "No support for wide ioPosMode" };
  476. static BooleanTable gPowerSwitchBooleanTable = { "Supports power switching", "No support for power switching" };
  477. static BooleanTable gHighPowerBooleanTable = { "In high power mode", "In low power mode" };
  478. static BooleanTable gSupportsPowerControlBooleanTable = { "Supports power control", "No support for power control" };
  479.  
  480. #pragma mark Flag Tables
  481.  
  482. // Flag results from various selectors.
  483.  
  484. static FlagElement gPCXFlags[] = {
  485.     { 0x01, "Supports PC Exchange calls", "No support for PC Exchange" },
  486.     { 0, nil, nil}
  487. };
  488.  
  489. static FlagElement gEjectFlags[] = {
  490.     { kRestartDontEject_Mask,     "Don't want eject at Restart",         "Wants eject at Restart" },
  491.     { kShutDownDontEject_Mask,     "Don't want eject at Shutdown",     "Wants eject at Shutdown" },
  492.     { 0, nil, nil}
  493. };
  494.  
  495. static FlagElement gVMOptionsFlags[] = {
  496.     { kAllowVMNoneMask,         "VM should never use this drive",         "VM may use this drive" },
  497.     { kAllowVMReadOnlyMask,     "VM may use this drive read-only",         "VM may not use this drive for read-only" },
  498.     { kAllowVMReadWriteMask,     "VM may use this drive read/write",     "VM may not use this drive for read/write" },
  499.     { 0, nil, nil}
  500. };
  501.  
  502. static FlagElement gPurgeFlags[] = {
  503.     { 1 << kbCloseOk,     "Close OK",         "Close not allowed" },
  504.     { 1 << kbRemoveOk,     "RemoveDriver OK",     "RemoveDriver not allowed" },
  505.     { 1 << kbPurgeOk,     "DisposePtr OK",     "DisposePtr not allowed" },
  506.     { 0, nil, nil}
  507. };
  508.  
  509. #pragma mark gGestaltList
  510.  
  511. // The primary list of Driver Gestalt selectors that we understand.
  512. // This table allows us to map selectors to their textual descriptions,
  513. // and allows us to print a Driver Gestalt response by dispatching
  514. // to the appropriate display routines. 
  515.  
  516. static GestaltElement gGestaltList[] = {
  517.     {kdgVersion,            "Version",                VersionDisplay, nil },
  518.     {kdgDeviceType,            "Device Type",            OSTypeDisplay, gDeviceTypeList },
  519.     {kdgInterface,            "Interface Type",        OSTypeDisplay, gInterfaceTypeList },
  520.     {kdgSync,                "Synchronous",            BooleanDisplay, &gSyncBooleanTable },
  521.     {kdgBoot,                "Boot",                    BootDisplay, nil },
  522.     {kdgWide,                "Wide",                    BooleanDisplay, &gWideBooleanTable },
  523.     {kdgPurge,                "Purge Permission",        PurgeDisplay, gPurgeFlags },
  524.     {kdgSupportsSwitching,    "Power Management",        BooleanDisplay, &gPowerSwitchBooleanTable },
  525.     {kdgMin3VPower,            "Min 3.3 V Power",        PowerDisplay, nil },
  526.     {kdgMin5VPower,            "Min 5 V Power",        PowerDisplay, nil },
  527.     {kdgMax3VPower,            "Max 3.3 V Power",        PowerDisplay, nil },
  528.     {kdgMax5VPower,            "Max 5 V Power",        PowerDisplay, nil },
  529.     {kdgInHighPower,        "High Power Mode",        BooleanDisplay, &gHighPowerBooleanTable },
  530.     {kdgSupportsPowerCtl,    "Power API Support",    BooleanDisplay, &gSupportsPowerControlBooleanTable },
  531.     {kdgAPI,            "PC Exchange API Support",    Flags16Display, gPCXFlags },
  532.     {kdgEject,            "Shutdown Eject Options",    Flags32Display, gEjectFlags },
  533.     {kdgFlush,                "Flush Options",        FlushDisplay, nil },
  534.     {kdgVMOptions,            "VM Options",            Flags32Display, gVMOptionsFlags },
  535.     {kdgMediaInfo,            "Media Information",    MediaInfoDisplay, nil},
  536.     {0,                        nil,                    nil, nil }
  537. };
  538.  
  539. /////////////////////////////////////////////////////////////////
  540. #pragma mark ----- User Interface Code -----
  541.  
  542. static void PrintListOfDrives(void)
  543.     // Prints a nicely formatted list of the drives
  544.     // available on this machine by walking the drive
  545.     // queue.
  546. {
  547.     DrvQElPtr thisDrv;
  548.     
  549.     printf("Drive List\n");
  550.     printf("  0) <<<all drives>>>\n");
  551.     
  552.     thisDrv = (DrvQElPtr) GetDrvQHdr()->qHead;
  553.     while (thisDrv != nil) {
  554.         printf("  %d) with driver %d “%#s”\n", thisDrv->dQDrive, thisDrv->dQRefNum, RefNumToName(thisDrv->dQRefNum));
  555.         thisDrv = (DrvQElPtr) thisDrv->qLink;
  556.     }
  557. }
  558.  
  559. static void PrintListOfSelectors(void)
  560.     // Prints a nicely formatted list of Driver Gestalt
  561.     // selectors that we know about by walking our
  562.     // gGestaltList table.
  563. {
  564.     ItemCount thisElement;
  565.  
  566.     printf("Selector List\n");
  567.     thisElement = 0;
  568.     while ( gGestaltList[thisElement].selector != 0 ) {
  569.         printf("  '%s' “%s”\n",
  570.                     OSTypeToString(gGestaltList[thisElement].selector),
  571.                     gGestaltList[thisElement].name
  572.                     );
  573.         thisElement += 1;
  574.     }
  575. }
  576.  
  577. static SInt16 GetDriveNumber(void)
  578.     // Asks the user to enter a drive number, returning
  579.     // a negative value on error, a positive value for a specific
  580.     // drive number, and 0 if the user wants to query all drives.
  581. {
  582.     SInt16 result;
  583.     char driveStr[256];
  584.     
  585.     PrintListOfDrives();
  586.     
  587.     printf("Enter a drive number:\n");
  588.     gets(driveStr);
  589.     if (driveStr[0] == 0) {
  590.         result = -1;
  591.     } else {
  592.         result = atoi(driveStr);
  593.     }
  594.     return result;
  595. }
  596.  
  597. typedef void (*ForEachDriveProc)(UInt32 refcon, SInt16 drive);
  598.  
  599. static void ForEachDriveDo(SInt16 drive, ForEachDriveProc proc, UInt32 refcon)
  600.     // This routine provides support for the users
  601.     // desire to issue a Driver Gestalt query on all drives,
  602.     // as specified by typing "0" in response to GetDriveNumber.
  603.     // That drive number is passed in as the drive parameter
  604.     // to this routine.  If it's non-zero, this routine calls
  605.     // the supplied proc with that drive as a parameter.  If drive
  606.     // is 0, this routine walks the drive queue, repeatedly calling
  607.     // proc, once for each drive.
  608. {
  609.     DrvQElPtr thisDrv;
  610.  
  611.     if (drive != 0) {
  612.         proc(refcon, drive);
  613.     } else {
  614.         thisDrv = (DrvQElPtr) GetDrvQHdr()->qHead;
  615.         while (thisDrv != nil) {
  616.             proc(refcon, thisDrv->dQDrive);
  617.             printf("\n");
  618.             thisDrv = (DrvQElPtr) thisDrv->qLink;
  619.         }
  620.     }
  621. }
  622.  
  623. static void SingleQuery(SInt16 drive, GestaltElement *element)
  624.     // Perform a single Driver Gestalt query on a single
  625.     // drive.  element is typically an entry from gGestaltList,
  626.     // which specifies which selector to query and how to print
  627.     // the result.
  628. {
  629.     OSErr err;
  630.     DriverGestaltParam pb;
  631.  
  632.     // Set up the parameter block.
  633.     
  634.     pb.ioVRefNum = drive;
  635.     pb.ioCRefNum = MapDriveToRefNum(drive);
  636.     pb.csCode = kDriverGestaltCode;
  637.     pb.driverGestaltSelector = element->selector;
  638.  
  639.     // Print out the query we're about to do.
  640.     
  641.     printf("'%s' (%s) on drive %d with driver %d “%#s”\n", 
  642.                         OSTypeToString(element->selector),
  643.                         element->name,
  644.                         drive,
  645.                         pb.ioCRefNum,
  646.                         RefNumToName(pb.ioCRefNum)
  647.                         );
  648.                         
  649.     // Check that the driver support Driver Gestalt.  If it doesn't,
  650.     // don't send the driver the query otherwise we might accidentally
  651.     // trigger some action we didn't expect.
  652.     
  653.     if ( DriveSupportsDriverGestalt(drive) ) {
  654.     
  655.         // The drive support Driver Gestalt.  Let's do the query
  656.         // and print out the result.
  657.         
  658.         err = PBStatusSync((ParmBlkPtr) &pb);
  659.         if (err == noErr) {
  660.             QAssert(element->responseDisplayRoutine != nil);
  661.             element->responseDisplayRoutine(&pb, element->responseDisplayArg);
  662.         } else {
  663.             printf("  Failed with error %d.\n", err);
  664.         }
  665.     } else {
  666.         printf("  Driver %d does not support Driver Gestalt.\n", pb.ioCRefNum);
  667.     }
  668.     
  669. }
  670.  
  671. static void OneQueryOnOneDrive(OSType selector, SInt16 drive)
  672.     // This routine issues one specific Drive Gestalt query,
  673.     // specified by selector, on one specific drive.  The basic
  674.     // operation is to search the gGestaltList array for the
  675.     // selector.  If we find it, we can pass the GestaltElement
  676.     // to SingleQuery, which uses it to format the response.
  677.     // If we can't find the query, we cook up our own local
  678.     // GestaltElement (which indicates that the response should
  679.     // be displayed by the DefaultDisplay routine) and use
  680.     // that instead.
  681. {
  682.     ItemCount thisElement;
  683.     Boolean found;
  684.     GestaltElement localElement;
  685.     
  686.     // Search gGestaltList for selector.
  687.     
  688.     thisElement = 0;
  689.     found = false;
  690.     while ( gGestaltList[thisElement].selector != 0 && ! found ) {
  691.         found = (gGestaltList[thisElement].selector == selector);
  692.         if ( ! found ) {
  693.             thisElement += 1;
  694.         }
  695.     }
  696.     
  697.     // If we found it, use it to issue the query, otherwise
  698.     // build our own local GestaltElement and issue the query
  699.     // with that.
  700.     
  701.     if (found) {
  702.         SingleQuery(drive, &gGestaltList[thisElement]);
  703.     } else {
  704.         localElement.selector = selector;
  705.         localElement.name = "Unknown";
  706.         localElement.responseDisplayRoutine = DefaultDisplay;
  707.         localElement.responseDisplayArg = nil;
  708.  
  709.         SingleQuery(drive, &localElement);
  710.     }
  711. }
  712.  
  713. static void AllQueriesOnOneDrive(UInt32 refcon, SInt16 drive)
  714.     // This routine queries all known Driver Gestalt selectors
  715.     // on a specific drive.  The refcon parameter is unused
  716.     // but it's required because this routine is a callback
  717.     // ForEachDriveDo.
  718. {
  719.     #pragma unused(refcon)
  720.     UInt32 thisElement;
  721.     DriverRefNum refNum;
  722.     
  723.     if ( DriveSupportsDriverGestalt(drive) ) {
  724.     
  725.         // Walk our global list of known Driver Gestalt selectors
  726.         // (gGestaltList) and call SingleQuery on each one.
  727.         
  728.         thisElement = 0;
  729.         while ( gGestaltList[thisElement].selector != 0 ) {
  730.             SingleQuery(drive, &gGestaltList[thisElement]);
  731.             thisElement += 1;
  732.         }
  733.     } else {
  734.     
  735.         // The driver does not support Driver Gestalt.  Stop now before
  736.         // generating a huge cascade of "Driver does not support Driver Gestalt"
  737.         // messages.
  738.         
  739.         refNum = MapDriveToRefNum(drive);
  740.         printf("Drive %d with driver %d “%#s” does not support Driver Gestalt.\n", 
  741.                     drive,
  742.                     refNum,
  743.                     RefNumToName(refNum)
  744.                     );
  745.     }
  746. }
  747.  
  748. static void DoOneQuery(void)
  749.     // This is a primary user interface entry point.  Ask
  750.     // the user for a drive and selector and then issue
  751.     // the query.
  752. {
  753.     SInt16 drive;
  754.     char   selectorStr[256];
  755.     OSType selector;
  756.     
  757.     drive = GetDriveNumber();
  758.     if (drive >= 0) {
  759.         do {
  760.             printf("Enter a selector (“?” for a list):\n");
  761.             gets(selectorStr);
  762.             if ( strcmp(selectorStr, "?") == 0 ) {
  763.                 PrintListOfSelectors();
  764.             }
  765.         } while ( strcmp(selectorStr, "?") == 0 );
  766.         if (selectorStr[0] != 0) {
  767.             selector = *((OSType *) &selectorStr[0]);
  768.             ForEachDriveDo(drive, OneQueryOnOneDrive, selector);
  769.         }
  770.     }
  771. }
  772.  
  773. static void DoAllQueries(void)
  774.     // This is a primary user interface entry point.
  775.     // Ask the user for a drive and then query all
  776.     // known Driver Gestalt selectors on that drive.
  777. {
  778.     SInt16 drive;
  779.     char   selectorStr[256];
  780.     OSType selector;
  781.     
  782.     drive = GetDriveNumber();
  783.     if (drive >= 0) {
  784.         selector = *((OSType *) &selectorStr[0]);
  785.         ForEachDriveDo(drive, AllQueriesOnOneDrive, 0);
  786.     }
  787. }
  788.  
  789. static void PrintHelp(void)
  790.     // This is a primary user interface entry point.
  791.     // Print the list of supported commands.
  792. {
  793.     printf("g) Issue a Driver Gestalt query\n");
  794.     printf("G) Query all known Driver Gestalt selectors\n");
  795.     printf("?) Help\n");
  796.     printf("q) Quit\n");
  797. }
  798.  
  799. void main(void)
  800.     // The main entry point.  A trivial console application
  801.     // that waits for a command to be typed and then performs
  802.     // the command.
  803. {
  804.     Boolean quitNow;
  805.     char    command[256];
  806.     
  807.     printf("Hello Cruel World!\n");
  808.     printf("\n");
  809.     printf("Driver Gestalt Explorer\n");
  810.     printf("-- A simple command line program for exploring\n");
  811.     printf("-- the Drive Gestalt values returned by block\n");
  812.     printf("-- device drivers\n");
  813.     printf("\n");
  814.     
  815.     PrintHelp();
  816.     quitNow = false;
  817.     do {
  818.         printf("\n");
  819.         printf("Enter a command:\n");
  820.         gets(command);
  821.         switch (command[0]) {
  822.             case 'g':
  823.                 DoOneQuery();
  824.                 break;
  825.             case 'G':
  826.                 DoAllQueries();
  827.                 break;
  828.             case '?':
  829.                 PrintHelp();
  830.                 break;
  831.             case 'q':
  832.                 quitNow = true;
  833.                 break;
  834.             default:
  835.                 printf("Huh?\n");
  836.                 break;
  837.         }
  838.     } while ( ! quitNow );
  839.     
  840.     printf("Done.  Press command-Q to Quit.\n");
  841. }
  842.